package cn.haoran.common.utils;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.cglib.beans.BeanMap;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


/**
 * 对象类型转换工具
 * Create by hanran on 2019/6/22
 */
public class ObjectConvertUtils {

    /**
     * map转object 可用在Object是String的场景下
     * 有bug 1）BigDicemal转换丢失精度
     * @param map
     * @param bean
     * @param <T>
     * @return
     */
    public static <T> T mapToBean(Map<String, Object> map, T bean){
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }


    /**
     * map转object 可用在Object是String的场景下
     * 有bug 1）BigDicemal转换丢失精度，2）java.util.Date类型无法转换（提供java.sql.Date的转换）
     * @param map
     * @param clazz
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T mapToObjectNew(Map<String, Object> map, Class<T> clazz) throws Exception {
        if(map == null) {
            return null;
        }
        Object object = clazz.newInstance();
        BeanUtils.populate(object, map);
        return (T)object;
    }

    /**
     * Map<String, String> 转为对象 T
     * @param map
     * @param clazz
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public static <T> T mapToObject(Map<String, Object> map, Class<T> clazz) throws Exception {
        if(map == null) {
            return null;
        }
        Object object = clazz.newInstance();
        // 获取声明属性
        Field[] fields = object.getClass().getDeclaredFields();
        for(Field field : fields) {
            // 获取属性修饰符
            int modify = field.getModifiers();
            // final和static修饰符的属性不处理
            if(Modifier.isFinal(modify) || Modifier.isStatic(modify)) {
                continue;
            }
            // 反射的对象在使用时取消 Java 语言访问检查
            field.setAccessible(true);
            // 设置值
            if(field.getType() == BigDecimal.class) {
                field.set(object, new BigDecimal(map.get(field.getName()).toString()));

            } else if(field.getType() == Long.class) {
                Integer value = (Integer)map.get(field.getName());
                if(value != null) {
                    field.set(object, value.longValue());
                }
            } else if(field.getType() == Date.class) {
                String dateValue = (String)map.get(field.getName());
                Date date = null;
                if(StringUtils.isNotBlank(dateValue)) {
                    String pattern = dateValue.length() == 10 ? "yyyy-MM-dd" : "yyyy-MM-dd HH:mm:ss";
                    date = DateUtils.stringToDate((String)map.get(field.getName()), pattern);
                }
                field.set(object, date);
            } else {
                field.set(object, map.get(field.getName()));
            }
        }
        return (T) object;
    }

    /**
     * 对象转map<String, Object>
     * @param obj
     * @return
     * @throws Exception
     */
    public static Map<String, Object> objectToMap(Object obj) throws Exception {
        if(obj == null){
            return null;
        }

        Map<String, Object> map = new HashMap<String, Object>();

        Field[] declaredFields = obj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            map.put(field.getName(), field.get(obj));
        }

        return map;
    }
}
